<?php

namespace Core\Common\Handler;

use Core\Common\Base\ConfigSource;
use Core\Common\Base\Consul;
use Core\Common\Base\Log;
use Core\Common\Route\Dispatcher;
use Core\Common\Util\Helper;

/**
 * 注册服务到consul
 *
 * @author baiyang@ibantang.com
 */
class ConsulHandler
{
    // 发出停止信号后, 是否直接KILL掉，还是要等待本次处理结束
    const TERM = true;
    const SLEEP = 1000000;

    private static $lastRegisterTime = 0; //上次注册时间
    private static $initRoute = false;
    private static $urls = null;
    private static $serverIp = "";
    private static $register = null;

    public static function run(\swoole_server $server)
    {
        // 如果还没有注册，或注册时间超过30，则检查注册信息是否正常
        if (self::$lastRegisterTime <= 0 || (time() - self::$lastRegisterTime) > 30) {
            self::register($server);
        }
        usleep(self::SLEEP);
        return true;
    }

    public static function register(\swoole_server $server)
    {
        $config = \Core\Common\Base\Config::config('consul');
        if (isset($config['enabled']) && !$config['enabled']) {
            self::$register = 2;
            return;
        }

        if (!self::$initRoute) {
            if (empty(self::$urls)) {
                Dispatcher::getInstance(CORE_WORK_ROOT)->initUri();
                self::$urls = Dispatcher::getInstance()->getRouteUriList();
            }
            self::$initRoute = true;
        }
        if (empty(self::$urls)) {
            self::$initRoute = false;
            return;
        }

        $address = $config['address'] ?? self::getIpAddress($server);
        if ($address == '' || $address == '127.0.0.1') {
            return;
        }
        $serverId = CORE_NAME . "." . $address . ":" . $server->port;

        // 查找当前服务是否在服务发现列表里
        $catalog = Consul::getInstance()->Catalog();
        list($srvInfo, $_, $err) = $catalog->service(CORE_NAME);
        if ($err) {
            Log::coreLog(["consul error", $err,]);
            return;
        }

        if (!empty($srvInfo)) {
            // 服务存在，不需要处理
            foreach ($srvInfo as $info) {
                if (empty($info)) {
                    continue;
                }
                if ($serverId == $info->getServiceID()) {
                    Log::coreLog(["check consul server_id, have exists", $serverId]);
                    return;
                }
            }
        }

        $meta = [
            'http' => (string)$server->port,
        ];
        foreach ($server->ports as $serverPort) {
            if ($serverPort->port != $server->port) {
                $meta['redis'] = (string)$serverPort->port;
            }
        }

        $tags = $config['tags'] ?? [];
        $intervalCheck = "10s";
        // 注册url到tags里
        if (isset($config['ares']) && $config['ares']) {
            $tags = array_merge($tags, array_map(function ($a) {
                return "urlprefix-/" . ltrim($a, "/ ");
            }, self::$urls));
            $intervalCheck = "3s";
        }

        $httpCheck = $config['http'] ?? "http://{$address}:{$server->port}/healthy_check";
        $baseInfo = [
            "ID" => $serverId,
            "Name" => CORE_NAME,
            'Address' => $address,
            'Port' => $server->port,
            'Meta' => $meta,
            'EnableTagOverride' => true,
            'Checks' => [
                [
                    'ID' => $serverId . "-http-check",
                    'NAME' => $serverId . "-http-check",
                    'HTTP' => $httpCheck,
                    'Interval' => $intervalCheck,
                    'DeregisterCriticalServiceAfter' => '3m',
                ],
            ],
        ];
        if (isset($config['meta'])) {
            $baseInfo['Meta'] += $config['meta'];
        }

        Log::coreLog([
            "register service to consul",
            $baseInfo,
            date("Y-m-d H:i:s"),
        ]);

        $baseInfo['Tags'] = $tags;
        try {
            Consul::getInstance()->registerService('v1/agent/service/register', $baseInfo);
            self::$lastRegisterTime = time();
        } catch (\Throwable $throwable) {
            Log::save('consul_service_register_error', $throwable->getMessage());
        }
    }

    public static function getIpAddress($server = null)
    {
        if (!empty(self::$serverIp)) {
            return self::$serverIp;
        }
        if ($server && $server instanceof \swoole_server && $server->host != '0.0.0.0') {
            $ip = $server->host;
        } else {
            $ip = Helper::getIpAddress();
        }
        self::$serverIp = $ip;
        return $ip;
    }
}
